/**
 * @brief 对监听套接字进行管理
 * @details
 * 1.accepter模块有一个由tcpServer设置的回调函数,该回调函数用于创建对应的connection以及设置各种回调函数,由tcpServer实现
 * 2.监听套接字需要实现channel的可读事件的回调函数,用于获取新连接
 */
#pragma once

#include "socket.hpp"
#include "eventLoop.hpp"

namespace hdp
{
    class Acceptor
    {
    private:
        Socket _socket;   // 同于创建监听套接字
        EventLoop *_loop; // 对于监听套接字进行事件监控
        Channel _channel; // 对于监控套接字进行事件管理

        using AcceptCallback = std::function<void(int, std::string &)>;
        AcceptCallback _accept_callback;

    private:
        int CreateServer(const uint16_t &port)
        {
            bool ret = _socket.CreateServer(port);
            assert(ret == true);
            return _socket.Fd();
        }

        // 监听套接字的读事件回调处理函数,获取新连接,调用_accept_callback函数进行新连接处理
        void HandleRead()
        {
            std::string clientIp;
            int newfd = _socket.Accept(clientIp);
            // 设置套接字非阻塞属性
            Socket::NonBlock(newfd);
            if (newfd < 0)
            {
                LOG_ERROR("accept new fd failed");
                return;
            }
            if (_accept_callback)
                _accept_callback(newfd, clientIp);
        }

    public:
        /*不能将启动读事件监控，放到构造函数中，必须在设置回调函数后，再去启动*/
        /*否则有可能造成启动监控后，立即有事件，处理的时候，回调函数还没设置：新连接得不到处理，且资源泄漏*/
        Acceptor(EventLoop *loop, const uint16_t &port)
            : _socket(CreateServer(port)), _loop(loop),
              _channel(_loop, _socket.Fd())
        {
            _channel.SetReadCallback(std::bind(&Acceptor::HandleRead, this));
        }
        void SetAcceptCallback(const AcceptCallback &cb)
        {
            _accept_callback = cb;
        }
        void Listen()
        {
            _channel.EnableRead();
        }
    };
}